/*
 * Copyright 2006-2008 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.martinimix.http.servlet;

import java.io.File;
import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.bluemartini.dna.BMContext;
import com.bluemartini.dna.BMException;
import com.bluemartini.dna.BMThreadManager;
import com.bluemartini.dna.BusinessObject;
import com.bluemartini.htmlapp.Content;
import com.bluemartini.htmlapp.HTMLContentUtil;
import com.bluemartini.util.HTMLVersionUtil;

/**
 * Provides a servlet filter that guarantees the availability of Blue Martini
 * managed content on an application server.
 * 
 * @author Scott Rossillo
 *
 */
public class ContentFilter implements Filter {

	private final static Log log = LogFactory.getLog(ContentFilter.class);

	private ServletContext servletContext;

	public void destroy() { }

	/* (non-Javadoc)
	 * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
	 */
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {

		HttpServletRequest httpRequest = (HttpServletRequest) request;
		String url = httpRequest.getRequestURI();

		if(!fileExists(url)) {
			if(log.isDebugEnabled()) {
				log.debug("Media needs to be fetched: "+ url);
			}
			try {
				setVersion();
				fetchMedia(url);
			} catch (BMException e) {
				log.error("Error retrieving media: " + url, e);
			}
		}

		chain.doFilter(request, response);
	}

	/**
	 * Stores the media designated by the given URL to the local
	 * document root.
	 */
	private void fetchMedia(String url) throws BMException {

		BusinessObject boContent = HTMLContentUtil.unversionPath(url);
		Content content;

		try {
			if(log.isDebugEnabled()) {
				log.debug("Fetching content " + boContent.getString("path"));
			}
			content = HTMLContentUtil.getContentByName(boContent.getString("path"));

			if(content != null && !content.isEmpty()) {
				if(log.isDebugEnabled()) {
					log.debug("Writing media " + content);
				}
				HTMLContentUtil.writeMedia(content, url, false);
			}
		} catch (BMException e) {
			throw new BMException("Unable to save media: " + url, e, null);
		}
	}

	/**
	 * Returns true if the content file located at the given URL exists.
	 */
	private boolean fileExists(String url) {

		return (new File(servletContext.getRealPath(url))).exists();        	
	}

	/* (non-Javadoc)
	 * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
	 */
	public void init(FilterConfig config) throws ServletException {

		servletContext = config.getServletContext();
		if(servletContext == null) {
			throw new ServletException("Unable to set servlet context!");
		}
	}

	/**
	 * Attempts to set the thread version, as required by Blue Martini.
	 */
	private void setVersion() {
		try {
			HTMLVersionUtil.getDefaultVersion();
		} catch (Throwable t) {
			String env = BMContext.getAppConfig().getString("using_env");
			Integer version;
			try {
				version = BMContext.getVersionIDForEnv(env);
				HTMLVersionUtil.getVersion(version);
				BMThreadManager.setCurrentVersionID(version);
			} catch (Throwable t2) {
				log.error("Unable to set thread version");
			}
		}
	}

}
